
#include <cstdio>
#include "member_BSocket.h"
#include "ISockets.h"

using namespace BWE;

#ifdef _LINUX_
#include <fcntl.h>
#endif

member_BSocket::member_BSocket(BSocket* socket)
{
	App_SocketStart();
	boss = socket;
	sock = 0;
	
#ifdef _WINDOWS_SYSTEM_
	sockState = BSocket::State_Closed;
	error = BSocket::Error_None;
	errorStr = 0;
#endif
}
member_BSocket::~member_BSocket()
{
	App_SocketClean();
}

bool member_BSocket::create(int domain, int type, int protocol)
{
#ifdef _LINUX_
	sock = ::socket(domain, type, protocol);
	if(sock == -1)
	{
		sock = 0;
		perror("create socket");
		return false;
	}
#endif
	
#ifdef _WINDOWS_SYSTEM_	
	sock = ::socket(domain, type, protocol);
	if (sock == INVALID_SOCKET)
	{
		perror("create socket failed.");
		return false;
	}
#endif
	return true;
}
bool member_BSocket::setnonblock()
{
#ifdef _LINUX_
	int opts = ::fcntl(sock, F_GETFL);
	if(opts == -1)
	{
		perror("fcntl(F_GETFL)");
		return false;
	}
	opts |= O_NONBLOCK;
	if(::fcntl(sock, F_SETFL, opts) == -1)
	{
		perror("fcntl(F_SETFL)");
		return false;
	}
#endif
	
#ifdef _WINDOWS_SYSTEM_	
	u_long mode = 0;
	int ret = ::ioctlsocket(sock, FIONBIO, &mode);
	if(ret == SOCKET_ERROR)
	{
		perror("ioctlsocket");
		return false;
	}
#endif
	return true;
}

bool member_BSocket::select(double seconds) const
{
	fd_set rfds;
	fd_set wfds;
	fd_set efds;

	FD_ZERO(&rfds);
	FD_ZERO(&wfds);
	FD_ZERO(&efds);

	FD_SET(socket_member(boss)->sock, &rfds);
	FD_SET(socket_member(boss)->sock, &wfds);
	FD_SET(socket_member(boss)->sock, &efds);

	timeval tv;
	if (seconds >= 0)
	{
		tv.tv_sec = seconds;
		tv.tv_usec = (seconds - tv.tv_sec) * 1000000;
	}

	int ret = ::select(socket_member(this)->sock, &rfds, &wfds, &efds, &tv);
	if (ret == -1)
	{
		perror("select");
		return false;
	}
	if (FD_ISSET(socket_member(this)->sock, &rfds))
		return true;
	if (FD_ISSET(socket_member(this)->sock, &wfds))
		return true;
	if (FD_ISSET(socket_member(this)->sock, &efds))
		return true;
	return false;
}

void member_BSocket::checkError()
{
#ifdef _WINDOWS_SYSTEM_	
	error = BSocket::Error_None;
	int errorCode = WSAGetLastError();
	switch (errorCode)
	{
	case WSAEBADF:
		errorStr = "The file handle supplied is not valid.";
		error = BSocket::Error_InvalidHandle;
		break;

	case WSAEFAULT:
		errorStr = "The system detected an invalid pointer address in attempting to use a pointer argument in a call.";
		error = BSocket::Error_BadArgment;
		break;
	case WSAECONNREFUSED:
		errorStr = "No connection could be made because the target machine actively refused it";
		error = BSocket::Error_Refused;
		break;
	case WSAECONNRESET:
		errorStr = "An existing connection was forcibly closed by the remote host.";
		error = BSocket::Error_ClosedForcibly;
		break;
	case WSAEISCONN:
		errorStr = "Socket is already connected.";
		error = BSocket::Error_ConnectAgain;
		break;
	default:
		break;
	}
#endif
	if (error != BSocket::Error_None)
	{
		boss->emit(Signal_Error, error);
	}
}

void member_BSocket::setState(BSocket::State newState)
{
	sockState = newState;
}
BSocket::State member_BSocket::state() const
{
	return sockState;
}
